#include <fstream>
#include <iostream>
#include "Poco/File.h"
#include "Poco/Exception.h"
#include "Encoding/Encoding.h"
#include "String/String.h"
#include "File.h"

using namespace SystemTool;

// Get file size
unsigned long long File::GetSize(std::string strFilePath)
{
    if (strFilePath.empty())
    {
        return 0;
    }

    String strFinalFilePath = strFilePath;
    strFinalFilePath.Replace("\\", "/");
    std::fstream in(strFinalFilePath.Data(), std::ios::binary | std::ios::in);
    if (!in.is_open())
    {
        return 0;
    }
    in.seekg(0, std::ios::end);
    unsigned long long uFileSize = in.tellg();
    return uFileSize;
}

// Set file writable
void File::SetWritable(std::string strFilePath, bool bIsWritable)
{
    if (strFilePath.empty())
    {
        return;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        FileHelper.setWriteable(bIsWritable);
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
}

// Set file read only
void File::SetReadonly(std::string strFilePath, bool bIsReadable)
{
    if (strFilePath.empty())
    {
        return;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        FileHelper.setReadOnly(bIsReadable);
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
}

// Set file excutable
void File::SetExcutable(std::string strFilePath, bool bIsExcutable)
{
    if (strFilePath.empty())
    {
        return;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        FileHelper.setExecutable(bIsExcutable);
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
}

// Copy file to a dir path
bool File::CopyTo(std::string strFilePath, std::string strDirPath, bool bIsOverWrite)
{
    if (strFilePath.empty())
    {
        return false;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");

        String strFinalDirPath = strDirPath;
        strFinalDirPath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        if (!bIsOverWrite)
        {
            FileHelper.copyTo(strFinalDirPath.Data(), Poco::File::OPT_FAIL_ON_OVERWRITE);
        }
        else
        {
            FileHelper.copyTo(strFinalDirPath.Data());
        }
        return true;
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
    return false;
}

// Move file to a dir path
bool File::MoveTo(std::string strFilePath, std::string strDirPath, bool bIsOverWrite)
{
    if (strFilePath.empty())
    {
        return false;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");

        String strFinalDirPath = strDirPath;
        strFinalDirPath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        if (!bIsOverWrite)
        {
            FileHelper.moveTo(strFinalDirPath.Data(), Poco::File::OPT_FAIL_ON_OVERWRITE);
        }
        else
        {
            FileHelper.moveTo(strFinalDirPath.Data());
        }
        return true;
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
    return false;
}

// Rename the file
bool File::Rename(std::string strFilePath, std::string strNewFilePath, bool bIsOverWrite)
{
    if (strFilePath.empty())
    {
        return false;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");

        String strFinalNewFilePath = strNewFilePath;
        strFinalNewFilePath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        if (!bIsOverWrite)
        {
            FileHelper.renameTo(strFinalNewFilePath.Data(), Poco::File::OPT_FAIL_ON_OVERWRITE);
        }
        else
        {
            FileHelper.renameTo(strFinalNewFilePath.Data());
        }
        return true;
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
    return false;
}

// Delete the file
bool File::Delete(std::string strFilePath)
{
    if (strFilePath.empty())
    {
        return false;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        FileHelper.remove();
        return true;
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
    return false;
}

// Create file by recursively
bool File::Create(std::string strFilePath, bool bIsRecursively)
{
    if (strFilePath.empty())
    {
        return false;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        if (!bIsRecursively)
        {
            return FileHelper.createFile();
        }

        // Get parent dir path
        int iPos = strFinalFilePath.FindLastOf("/");
        if (iPos == -1)
        {
            return false;
        }
        String strParentDirPath = strFinalFilePath.SubStr(0, iPos);

        // Create all dirs
        Poco::File DirFile(strParentDirPath.Data());
        DirFile.createDirectories();
        return FileHelper.createFile();
    }
    catch (Poco::FileExistsException &e)
    {
        return true;
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
    return false;
}

// Get file name
std::string File::GetFileName(std::string strFilePath)
{
    if (strFilePath.empty())
    {
        return "";
    }

    String strFinalFilePath = strFilePath;
    strFinalFilePath.Replace("\\", "/");
    int iPos = strFinalFilePath.FindLastOf("/");
    if (iPos == -1)
    {
        return "";
    }
    String strName = strFinalFilePath.SubStr(iPos + 1);
    return strName.Data();
}

// Get file's parent path
std::string File::GetFileParentDirPath(std::string strFilePath)
{
    if (strFilePath.empty())
    {
        return "";
    }

    String strFinalFilePath = strFilePath;
    strFinalFilePath.Replace("\\", "/");
    int iPos = strFinalFilePath.FindLastOf("/");
    if (iPos == -1)
    {
        return "";
    }
    String strDirPath = strFinalFilePath.SubStr(0, iPos);
    return strDirPath.Data();
}

// Is file existed
bool File::IsExisted(std::string strFilePath)
{
    if (strFilePath.empty())
    {
        return false;
    }

    try
    {
        String strFinalFilePath = strFilePath;
        strFinalFilePath.Replace("\\", "/");
        Poco::File FileHelper(strFinalFilePath.Data());
        return FileHelper.exists();
    }
    catch (Poco::Exception &e)
    {
        std::cout << "Err Happend with:" << e.displayText() << std::endl;
    }
    return false;
}
